package 不可变类.retrofit;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * sms router
 *
 * @author zhenglian
 */
public class SmsRouter {

    /**
     * 短信网关对象， 使用volatile修饰来保证其他线程可见
     */
    private static volatile SmsRouter instance = new SmsRouter();

    /**
     * 短信服务商信息的map， key对应的是优先级
     */
    private final Map<Integer, SmsInfo> smsInfoRouteMap;

    public static SmsRouter getInstance() {
        return instance;
    }

    public static void setInstance(SmsRouter smsRouter) {
        instance = smsRouter;
    }


    /**
     * 获取短信服务商
     *
     * @return 短信服务商map
     */
    public Map<Integer, SmsInfo> getSmsInfoRouteMap() {
        // 防止对短信路由信息更改， 进行防御性复制
        return Collections.unmodifiableMap(deepCopy(smsInfoRouteMap));
    }

    private Map<Integer, SmsInfo> deepCopy(Map<Integer, SmsInfo> smsInfoRouteMap) {
        Map<Integer, SmsInfo> result = new HashMap<>(smsInfoRouteMap.size());

        for (Map.Entry<Integer, SmsInfo> entry : smsInfoRouteMap.entrySet()) {
            result.put(entry.getKey(), new SmsInfo(entry.getValue()));
        }

        return result;
    }

    public SmsRouter() {
        this.smsInfoRouteMap = this.loadSmsInfoRouteMapFromDb();
    }

    public Map<Integer, SmsInfo> getSmsInfoMap() {
        return smsInfoRouteMap;
    }

    /**
     * 从数据库加载短信服务商信息
     *
     * @return 短信中心的路由信息
     */
    private Map<Integer, SmsInfo> loadSmsInfoRouteMapFromDb() {
        // 初始化， 模拟从数据库中加载
        Map<Integer, SmsInfo> routeMap = new HashMap<>();

        routeMap.put(1, new SmsInfo(1L, "https://www.aliyun.com", 180L));
        routeMap.put(2, new SmsInfo(2L, "https://cloud.tencent.com", 180L));
        routeMap.put(3, new SmsInfo(3L, "https://cloud.baidu.com", 180L));

        return routeMap;
    }

    public void changeRounteInfo() {
        // 伪代码，数据库更新路由信息
        // updateSmsRounteInfoList();

        // 此时设置了新的路由对象，则会重新加载数据， 因为防御性复制，则当更新完成后，还没有加载进内存的时候，获取的还是之前的数据，但是数据不会错乱。符合场景
        SmsRouter.setInstance(new SmsRouter());
    }

    public static void main(String[] args) {
        SmsRouter smsRouter = SmsRouter.getInstance();
        smsRouter.changeRounteInfo();
    }

}
